QuickTime 3 Reference

Previous | Chapter Top | Chapter Contents | Next

Decompressing Bands

Your image decompressor component must implement the ImageCodecBeginBand and ImageCodecDrawBand functions for decompressing bands. It can also implement the ImageCodecEndBand function to be information that decompression of a band is complete. It receives these calls from the base image decompressor when decompression of either a complete frame or an individual band needs to be performed.

Implementing ImageCodecBeginBand

The ImageCodecBeginBand function allows your image decompressor component to save information about a band before decompressing it. For example, your image decompressor component can change the value of the codecData pointer if not all of the data for the band needs to be decompressed. The base image decompressor preserves any changes your image decompressor component makes to any of the fields in the ImageSubCodecDecompressRecord or CodecDecompressParams structures.

The ImageCodecBeginBand function is never called at interrupt time. If your component supports asynchronous scheduled decompression, it may receive more than one ImageCodecBeginBand call before receiving an ImageCodecDrawBand call.

A sample implementation of ImageCodecBeginBand is shown in Listing 4 .

Listing 4 Sample implementation of ImageCodecBeginBand

pascal ComponentResult ImageCodecBeginBand (
                          ComponentInstance ci,
                          CodecDecompressParams *p,
                          ImageSubCodecDecompressRecord *drp,
                          long flags)
{
    ExampleDecompressRecord *mydrp = drp->userDecompressRecord;
    long            numLines,numStrips;
    long            stripBytes;
    short           width;
    short           y;
    OSErr           result = noErr;
    Ptr             cDataPtr;
    
    /* initialize some local variables */
    
    width = (*p->imageDescription)->width;
    numLines = p->stopLine - p->startLine;/* number of scanlines in */
                                          /* this band */
    numStrips = (numLines+1)>>1;/* number of strips in this band */
    stripBytes = ((width+1)>>1) * 5;/* number of bytes in one */
                                    /* strip of blocks */
    cDataPtr = drp->codecData;
    
    /*
     *  If skipping some data, just skip it here. We can tell because
     *  firstBandInFrame says this is the first band for a new frame, and
     *  if startLine is not zero, then that many lines were clipped out.
     */

    if ( (p->conditionFlags & codecConditionFirstBand) && p->startLine != 0 ) {
        if ( p->dataProcRecord.dataProc ) {
            for ( y=0; y < p->startLine>>1; y++ ) {
                if (
(result=CallICMDataProc(p->dataProcRecord.dataProc,&cDataPtr,stripBytes,
                        drp->dataProcRecord.dataRefCon)) != noErr ) {
                    result = codecSpoolErr;
                    goto bail;
                }
                cDataPtr += stripBytes;
            }
        } else
            cDataPtr += (p->startLine>>1) * stripBytes;
    }
    
    drp->codecData = cDataPtr;
    mydrp->width = width;
    mydrp->numStrips = numStrips;
    mydrp->srcDataIncrement = stripBytes;
    mydrp->baseAddrIncrement = drp->rowBytes<<1;
    mydrp->glob = (void *)storage;

    /* figure out our dest pixel format and select the
       correct DecompressStripProc */
    switch(p->dstPixMap.pixelFormat) {
        case 0:                     // old case where planebytes
                                    // is not set by codecmanager
        case k32ARGBPixelFormat:
            mydrp->decompressStripProc = DecompressStrip32ARGB;
            break;
        case k32ABGRPixelFormat:
            mydrp->decompressStripProc = DecompressStrip32ABGR;
            break;
        case k32BGRAPixelFormat:
            mydrp->decompressStripProc = DecompressStrip32BGRA;
            break;
        case k32RGBAPixelFormat:
            mydrp->decompressStripProc = DecompressStrip32RGBA;
            break;
        default:
            bail;
            break;
    }

bail:
    return result;
}

Implementing ImageCodecDrawBand

When the base image decompressor calls your image decompressor component's ImageCodecDrawBand function, your component must perform the decompression specified by the fields of the ImageSubCodecDecompressRecord structure. The structure includes any changes your component made to it when performing the ImageCodecBeginBand function.

If the ImageSubCodecDecompressRecord structure specifies either a progress function or a data-loading function, the base image decompressor never calls the ImageCodecDrawBand function at interrupt time. If not, the base image decompressor may call the ImageCodecDrawBand function at interrupt time.

If the ImageSubCodecDecompressRecord structure specifies a progress function, the base image decompressor handles codecProgressOpen and codecProgressClose calls, and your image decompressor component must not implement these functions.

If your component supports asynchronous scheduled decompression, it may receive more than one ImageCodecBeginBand call before receiving an ImageCodecDrawBand call.

A sample implementation of ImageCodecDrawBand is shown in Listing 5 .

Listing 5 Sample implementation of ImageCodecDrawBand

pascal ComponentResult ImageCodecDrawBand (
                          ComponentInstance ci,
                          ImageSubCodecDecompressRecord *drp)
{
    ExampleDecompressRecord *mydrp = drp->userDecompressRecord;
    short y;
    Ptr cDataPtr = drp->codecData;// compressed data pointer;
    Ptr baseAddr = drp->baseAddr;// base address of dest PixMap;
    SInt8 mmuMode = true32b;// we want to be in 32-bit mode
    OSErr err = noErr;

    for (y = 0; y < mydrp->numStrips; y++) {
        if (drp->dataProcRecord.dataProc) {
            if ( (err = CallICMDataProc(drp->dataProcRecord.dataProc,&cDataPtr,
                mydrp->srcDataIncrement,
                drp->dataProcRecord.dataRefCon)) != noErr ) {
                err = codecSpoolErr;
                goto bail;
            }
        }

        SwapMMUMode(&mmuMode);// put us in 32-bit mode
        (mydrp->decompressStripProc)(cDataPtr,baseAddr,(short)drp->rowBytes,
        (short)mydrp->width,glob->sharedGlob);
        SwapMMUMode(&mmuMode);// put us back

        baseAddr += mydrp->baseAddrIncrement;
        cDataPtr += mydrp->srcDataIncrement;

        if (drp->progressProcRecord.progressProc) {
            if ( (err = CallICMProgressProc(drp->progressProcRecord.progressProc,
                    codecProgressUpdatePercent,
                    FixDiv ( y, mydrp->numStrips),
                drp->progressProcRecord.progressRefCon)) != noErr ) {
                err = codecAbortErr;
                goto bail;
            }
        }
    }

bail:
    return err;
}

Implementing ImageCodecEndBand

Your image decompressor component is not required to implement the ImageCodecEndBand function. If it does, the base image decompressor calls the function when the decompression of a band is complete or is terminated by the Image Compression Manager. The call simply notifies your component that decompression is finished. After your component handles the call, it can perform any tasks that are necessary when decompression is finished, such as disposing of data structures that are no longer used, after receiving notification. Note that because the ImageCodecEndBand function can be called at interrupt time, your image decompressor component cannot use this function to dispose of data structures; this must occur after handling the function.


© 1997 Apple Computer, Inc.

Previous | Chapter Top | Chapter Contents | Next